package com.zzh.l02_mediaprojection

import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.Resources
import android.hardware.display.DisplayManager
import android.media.MediaCodec
import android.media.MediaCodecInfo
import android.media.MediaCodecList
import android.media.MediaFormat
import android.media.projection.MediaProjection
import android.media.projection.MediaProjectionManager
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.zzh.l02_mediaprojection.databinding.ActivityMainBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File
import java.io.FileOutputStream
import java.io.FileWriter
import java.nio.ByteBuffer

class MainActivity : AppCompatActivity() {
    private lateinit var mainBinding: ActivityMainBinding

    private lateinit var mediaProjectionManager: MediaProjectionManager
    private lateinit var mediaProjection: MediaProjection
    private lateinit var mediaCodec: MediaCodec
    private var startFlag = true

    private var totalSize = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mainBinding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(mainBinding.root)
        checkPermission()

        mainBinding.btStartCapture.setOnClickListener {
            deleteFile()
            //获取录屏系统服务
            mediaProjectionManager =
                getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
            //申请录屏权限，弹出录屏权限的对话框
            val intent = mediaProjectionManager.createScreenCaptureIntent()
            startActivityForResult(intent, 100)
        }

        mainBinding.btStopCapture.setOnClickListener {
            startFlag = false
            mediaProjection.stop()
            mediaCodec.release()
            // mediaCodec.stop()
        }

    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == 100 && resultCode == Activity.RESULT_OK && data != null) {
            //获得录屏数据,Android高版本有权限问题，api27data
            mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data)
            //编码成h264流
            try {
                encodeScreen()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }


    private fun encodeScreen() {
        //获取屏幕宽高
        val dm = Resources.getSystem().displayMetrics
        //防止宽高出现单数而报错
        val screenWidth = if (dm.widthPixels % 2 == 0) dm.widthPixels else dm.widthPixels - 1
        val screenHeight =if (dm.heightPixels % 2 == 0) dm.heightPixels else dm.heightPixels - 1
        //创建h264编码器
        mediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC)
        //在某些手机时，创建时必须reset一下，否则会报错
        // mediaCodec.reset()

        val format =
            MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, screenWidth, screenHeight)

        //配置编码帧率
        format.setInteger(MediaFormat.KEY_FRAME_RATE, 15)
        //配置编码码率1000kb/s
        format.setInteger(MediaFormat.KEY_BIT_RATE, 1000_000)
        //配置关键帧I帧间隔为2秒一个
        format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2)
        //配置编码颜色格式，YUV420/NV21等，这里录制的屏幕数据是graphicbuffer元数据使用COLOR_FormatSurface
        format.setInteger(
            MediaFormat.KEY_COLOR_FORMAT,
            MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface
        )


        mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
        //通过MediaCodec提供surface,让屏幕录制的数据输入到MediaCodec
        val meidaSurface = mediaCodec.createInputSurface()

        lifecycleScope.launchWhenResumed {
            withContext(Dispatchers.IO) {
                mediaCodec.start()
                //让mediaProjection输出到MediaCodec
                mediaProjection.createVirtualDisplay(
                    "screen-codec",
                    screenWidth, //输出录屏宽大小
                    screenHeight, //输出录屏高大小
                    1,  //输出录屏dpi数，不放大缩小就直接1
                    DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC, //输出到虚拟的画布标记
                    meidaSurface, //MeidaCodec画布
                    null,
                    null
                )

                //创建一个存放编码的数据缓冲区
                try {
                    val bufferInfo = MediaCodec.BufferInfo()
                    while (startFlag) {
                        //100毫秒(100_000微妙)内完成编码的数据，放到bufferInfo内，并返回编码完成的通道编号,没有完成会返回-1
                        val channal = mediaCodec.dequeueOutputBuffer(bufferInfo, 100_000)
                        if (channal >= 0) {
                            //获取对应通道编码完成的字节数据
                            val buffer: ByteBuffer? = mediaCodec.getOutputBuffer(channal)
                            //取出编码完成的字节数据,大小为缓冲去的大小
                            val outData = ByteArray(bufferInfo.size)
                            buffer?.get(outData)
                            //写入成h264码流文件
                            writeH264Bytes(outData)
                            //写入成字节数组的文本
                            writeHexContent(outData)
                            totalSize += bufferInfo.size
                            Log.i("TAG_MainActivity", "已编码：${totalSize / 1024 / 1024f}MB")
                            //编码完成后释放编码完成的通道
                            mediaCodec.releaseOutputBuffer(channal, false)
                        }
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }
        }
    }


    val h264 = "${Environment.getExternalStorageDirectory()}/screen.h264"
    val txt = "${Environment.getExternalStorageDirectory()}/screen.txt"

    //生成二进制流数据文件，使其可以播放
    private fun writeH264Bytes(bytes: ByteArray) {
        FileOutputStream(h264, true).use {
            it.write(bytes)
            it.write('\n'.code)
        }
    }

    //字节数组以16进制写入文本文件
    private fun writeHexContent(bytes: ByteArray) {
        val HEX_CHAR_TABLE = "0123456789ABCDEF".toCharArray()
        val sb = StringBuilder()
        bytes.forEach {
            //byte取值范围为-128-127，遇到负数要转为正数
            val byte = (it.toInt() and 0xff)
            //取出字节的高4位转为16进制表示
            val hight4 = (byte and 0xf0) shr 4
            sb.append(HEX_CHAR_TABLE[hight4])
            //取出字节的低4位转为16进制表示
            val low4 = byte and 0x0f
            sb.append(HEX_CHAR_TABLE[low4])
            sb.append(" ")
        }
        FileWriter(txt, true).use {
            it.write(sb.toString())
            it.write("\n")
        }
    }

    //删除之前生成的h264文件和文本文件
    private fun deleteFile() {
        File(h264).apply {
            if (exists()) delete()
        }
        File(txt).apply {
            if (exists()) delete()
        }
    }

    private fun checkPermission(): Boolean {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(
                Manifest.permission.WRITE_EXTERNAL_STORAGE
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            requestPermissions(
                arrayOf(
                    Manifest.permission.READ_EXTERNAL_STORAGE,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE
                ), 1
            );

        }
        return false
    }
}